#include <libdswmemory/dswmemory.h>

CDswmemory::CDswmemory(int nBlockSize, int nTotalSize)
: m_pTotalBuffer(NULL)
, m_pTotalIndex(NULL)
, m_nBlockSize((nBlockSize % DSWPACK) ? ((DSWPACK - (nBlockSize % DSWPACK)) + nBlockSize) : nBlockSize)
, m_nTotalSize((nTotalSize % DSWPACK) ? ((DSWPACK - (nTotalSize % DSWPACK)) + nTotalSize) : nTotalSize)
{
	int nBlockNums = m_nTotalSize / m_nBlockSize;
	m_pTotalBuffer = (char*)new char[m_nTotalSize];
	m_pTotalIndex = (LPST_DSWMEMORY_T)new ST_DSWMEMORY_T[nBlockNums];
	int nKeyIndex = 0;
	char* pPos = m_pTotalBuffer;
	while(--nBlockNums >= 0){
		m_pTotalIndex[nBlockNums].nKeyIndex = nKeyIndex;
		m_pTotalIndex[nBlockNums].pBuffer = pPos;
		pPos += m_nBlockSize;
		m_pTotalIndex[nBlockNums].pNext = NULL;
		m_pTotalIndex[nBlockNums].pFuncFree = CDswmemory::cbDswMemoryFree;
		m_pTotalIndex[nBlockNums].nUsedsize = 0;
		m_pTotalIndex[nBlockNums].nTotalsize = m_nBlockSize;
		m_list_memory.push_back(&m_pTotalIndex[nBlockNums]);
		nKeyIndex++;
	}
	pthread_mutex_init(&m_nlock, NULL);
	printf("Malloc memory %d bytes, %d blocks\n", m_nTotalSize, m_list_memory.size());
}

CDswmemory::~CDswmemory()
{
	if (!m_list_memory.empty())
		m_list_memory.clear();
	if (m_pTotalIndex)
		delete m_pTotalIndex;
	if (m_pTotalBuffer)
		delete m_pTotalBuffer;
	pthread_mutex_destroy(&m_nlock);
	printf("Free memory %d bytes!\n", m_nTotalSize);
}

void CDswmemory::DswMemoryFree(LPST_DSWMEMORY_T pMemory)
{
	LPST_DSWMEMORY_T pNext = pMemory->pNext;
	pMemory->pNext = NULL;
	pMemory->nUsedsize = 0;
	pMemory->nTotalsize = m_nBlockSize;
	m_list_memory.push_back(pMemory);
	if (pNext)
		DswMemoryFree(pNext);
}

void* CDswmemory::DswMemoryNew(int nSize)
{
	int nRealSize = ((nSize % m_nBlockSize) ? ((m_nBlockSize - (nSize % m_nBlockSize)) + nSize) : nSize);
	int nNeedBlocks = nRealSize / m_nBlockSize;
	LPST_DSWMEMORY_T pRet = NULL;
	MUTEX_LOCK(&m_nlock);
	if (m_list_memory.size() >= nNeedBlocks){
		LPST_DSWMEMORY_T pPreNode = NULL;
		while(--nNeedBlocks >= 0){
			LPST_DSWMEMORY_T pNode = m_list_memory.front();
			m_list_memory.pop_front();
			pNode->nUsedsize = 0;
			pNode->nTotalsize = nRealSize;
			pNode->pNext = NULL;
			if (pPreNode)
				pPreNode->pNext = pNode;
			pPreNode = pNode;
			if (pRet == NULL)
				pRet = pNode;
		}
	}
	MUTEX_UNLOCK(&m_nlock);
	return (void*)pRet;
}

void CDswmemory::DswMemoryDelete(void* pMem)
{
	LPST_DSWMEMORY_T pMemory = (LPST_DSWMEMORY_T)pMem;
	MUTEX_LOCK(&m_nlock);
	pMemory->pFuncFree(pMemory, this);
	MUTEX_UNLOCK(&m_nlock);
}

int CDswmemory::DswMemoryCpy(char* pSrc, int nSize, void* pDest)
{
	int nCpSize = 0;
	LPST_DSWMEMORY_T pMemory = (LPST_DSWMEMORY_T)pDest;
	if (pMemory->nTotalsize < nSize){
		printf("The dest memory is too small!\n");
		return -1;
	}
	while(nSize > m_nBlockSize){
		memcpy(pMemory->pBuffer, pSrc, m_nBlockSize);
		pMemory->nUsedsize = m_nBlockSize;
		pMemory = pMemory->pNext;
		nCpSize += m_nBlockSize;
		nSize -= m_nBlockSize;
		pSrc += m_nBlockSize;
	}
	if (nSize > 0){
		memcpy(pMemory->pBuffer, pSrc, nSize);
		pMemory->nUsedsize = nSize;
		nCpSize += nSize;
	}
	return nCpSize;
}

int CDswmemory::DswMemoryCpy(void* pSrc, char* pDest, int nDestLen)
{
	int nCpSize = 0;
	LPST_DSWMEMORY_T pMemory = (LPST_DSWMEMORY_T)pSrc;
	if (nDestLen < pMemory->nTotalsize)
		return -1;
	char* pPos = pDest;
	while(pMemory){
		memcpy(pPos, pMemory->pBuffer, pMemory->nUsedsize);
		pPos += pMemory->nUsedsize;
		nCpSize += pMemory->nUsedsize;
		pMemory = pMemory->pNext;
	}
	return nCpSize;
}

int CDswmemory::DswMemorySet(void* pMem, unsigned char nData, int nSize)
{
	LPST_DSWMEMORY_T pMemory = (LPST_DSWMEMORY_T)pMem;
	int nRet = 0;
	if (nSize > pMemory->nTotalsize)
		return -1;
	while(nSize > m_nBlockSize){
		memset(pMemory->pBuffer, nData, m_nBlockSize);
		pMemory->nUsedsize = m_nBlockSize;
		pMemory = pMemory->pNext;
		nSize -= m_nBlockSize;
		nRet += m_nBlockSize;
	}
	if (nSize > 0){
		pMemory->nUsedsize = nSize;
		memset(pMemory->pBuffer, nData, nSize);
		nRet += nSize;
	}
	return nRet;
}

int CDswmemory::DswMemoryGetSize(void* pMem)
{
	int nSize = 0;
	LPST_DSWMEMORY_T pMemory = (LPST_DSWMEMORY_T)pMem;
	while(pMemory){
		nSize += pMemory->nUsedsize;
		pMemory = pMemory->pNext;
	}
	return nSize;	
}




